#!/usr/bin/python

import os
import sys

temp_path = sys.path[0]
if temp_path:
    sys.path.insert(0, os.path.join(temp_path, '..', '..', 'SmartMeshSDK'))

import Tkinter
import dustGuiLib
import dustFrame
from dustStyle import dustStyle
from ApiDefinition import ApiDefinition
from ApiException import CommandError

class dustFrameFields(dustFrame.dustFrame):
    '''
    \ingroup guiLib
    
    \brief A frame which displays fields graphically.
    '''
    
    def __init__(self,parentElem,guiLock,type,frameName="fields",row=0,column=0):
        
        # record variables
        self.type = type
        
        # init parent
        dustFrame.dustFrame.__init__(self,parentElem,guiLock,frameName,row,column,scrollable=True)
        
        # row 0: headerLabel
        self.headerLabel = dustGuiLib.Label(self.container,
                                         text='')
        self._add(self.headerLabel,0,0)
        
        # row 1: fieldsFrame
        self.fieldsFrame = Tkinter.Frame(self.container)
        self._add(self.fieldsFrame,1,0)
                  
    #======================== public ==========================================
    
    def indicateFields(self,commandArray,fields):
        
        # write commandArray in the header label
        self.guiLock.acquire()
        self.headerLabel.configure(text='.'.join(commandArray))
        self.headerLabel.configure(bg=dustStyle.COLOR_BG)
        self.guiLock.release()
        
        # display the fields in the fieldsFrame
        self._displayFields(self.type,
                            commandArray,
                            fields)
    
    def indicateError(self,errorText):
        
        # write APIError in the header label
        self.guiLock.acquire()
        self.headerLabel.configure(text=str(errorText))
        self.headerLabel.configure(bg=dustStyle.COLOR_ERROR)
        self.guiLock.release()
        
        # clear the GUI elems
        self._clearGuiElems()
    
    #======================== private =========================================
    
    def _displayFields(self,type,nameArray,fields):
        '''
        \brief Display a response or notification as GUI elements. If the fields
               contain a list of elements, each one is displayed as a separate
               line in the resulting table.
        
        \param type      Set to ApiDefinition.COMMAND when displaying a response, 
                         ApiDefinition.NOTIFICATION when displaying a notification.
        \param nameArray The name array of the response or notification received from
                         the connector.
        \param fields    The fields received from the connector.
        '''
        
        # clear the old elems
        self._clearGuiElems()
        
        # display information row by row
        if   isinstance(fields,dict):
            rowNumber = 0
            firstRow  = True
            lastRow   = True
            self._displayFieldsRow(rowNumber,firstRow,lastRow,type,nameArray,fields)
        elif isinstance(fields,list):
            for rowNumber in range(len(fields)):
                firstRow = (rowNumber==0)
                lastRow  = (rowNumber==len(fields)-1)
                self._displayFieldsRow(rowNumber,firstRow,lastRow,type,nameArray,fields[rowNumber])
        else:
            raise SystemError("fields expected to be a list of dictionary, {0} is not".format(fields))
        
    def _displayFieldsRow(self,rowNumber,firstRow,lastRow,type,nameArray,fields):
        
        c = {
                'commandName'         : None,
                'fieldNames'          : [],
                'fieldNamesGui'       : [],
                'fieldFormats'        : [],
                'fieldFormatsGui'     : [],
                'fieldLengths'        : [],
                'fieldOptions'        : [],
                'fieldValuesGui'      : [],
                'fieldValuesString'   : [],
                'fieldValuesRaw'      : [],
                'fieldValues'         : [],
                'commandORbuttonGui'  : None,
            }
        
        # add elements for fields
        for i in range(len(nameArray)):
            tempName = nameArray[:i+1]
            
            try:
                temp_fieldNames   =  self.apiDef.getResponseFieldNames(
                                         type,
                                        tempName
                                      )
                temp_fieldFormats = [self.apiDef.getResponseFieldFormat(
                                         type,
                                         tempName,
                                         fieldName
                                         )
                                            for fieldName in temp_fieldNames]
                temp_fieldLengths = [self.apiDef.getResponseFieldLength(
                                        type,
                                        tempName,
                                        fieldName)
                                            for fieldName in temp_fieldNames]
                temp_fieldOptions = [self.apiDef.getResponseFieldOptions(
                                        type,
                                        tempName,
                                        fieldName)
                                            for fieldName in temp_fieldNames]
                                            
                c['fieldNames']   += temp_fieldNames
                c['fieldFormats'] += temp_fieldFormats
                c['fieldLengths'] += temp_fieldLengths
                c['fieldOptions'] += temp_fieldOptions
                
            except CommandError as err:
                print str(err)
                return
        
        # add values
        for i in range(len(c['fieldNames'])):
            fieldName = c['fieldNames'][i]
            try:
                fieldValue  = fields[fieldName]
            except KeyError:
                fieldValue  = "N.A."
                
            if c['fieldFormats'][i]=='hexdata':
                fieldString = self._hexdata2string(fieldValue,0,len(fieldValue))
            else:
                fieldString = str(fieldValue)
            try:
                description = self.apiDef.fieldValueToDesc(type,
                                                      nameArray,
                                                      fieldName,
                                                      fieldValue)
                fieldString = description+" ("+fieldString+")"
            except CommandError as err:
                if err.errorCode!=CommandError.VALUE_NOT_IN_OPTIONS:
                    raise
            c['fieldValues'].append(fieldString)
        
        headercolor = self._getHeaderColor()
        
        self.guiLock.acquire()
        for i in range(len(c['fieldNames'])):
            if c['fieldNames'][i] in ApiDefinition.ApiDefinition.RESERVED:
                continue
            # row: name (iff first row)
            if firstRow:
                c['fieldNamesGui'].append(dustGuiLib.Label(
                    self.fieldsFrame,
                    text=c['fieldNames'][i],
                    bg=dustStyle.COLOR_BG,
                    relief=Tkinter.RIDGE,
                    borderwidth=1,
                    background=headercolor,
                    padx=3,
                    pady=3))
                c['fieldNamesGui'][-1].grid(row=0,column=i,
                    sticky=Tkinter.W+Tkinter.E)
            # row: value
            c['fieldValuesString'].append(None)
            c['fieldValuesGui'].append(dustGuiLib.Label(
                self.fieldsFrame,
                text=c['fieldValues'][i],
                bg=dustStyle.COLOR_BG,
                relief=Tkinter.RIDGE,
                borderwidth=1,
                padx=3,
                pady=3))
            c['fieldValuesGui'][-1].grid(row=rowNumber+1,column=i,
                sticky=Tkinter.W+Tkinter.E)
            # row: format and length (iff last row)
            if lastRow:
                fieldFormatsString = c['fieldFormats'][i]
                if c['fieldLengths'][i]:
                    fieldFormatsString += " ("+str(c['fieldLengths'][i])+"B)"
                c['fieldFormatsGui'].append(dustGuiLib.Label(
                    self.fieldsFrame,
                    text=fieldFormatsString,
                    bg=dustStyle.COLOR_BG,
                    relief=Tkinter.RIDGE,
                    borderwidth=1,
                    padx=3,
                    pady=3))
                c['fieldFormatsGui'][-1].grid(row=rowNumber+2,column=i,
                    sticky=Tkinter.W+Tkinter.E)
        self.guiLock.release()
        
        # add to the guiElems
        self.guiElems.append(c)
        